package com.knowledge.business.controller;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.knowledge.business.domain.*;
import com.knowledge.business.service.*;
import com.knowledge.business.service.impl.DocumentVectorService;
import com.knowledge.business.service.impl.TKeywordsServiceImpl;
import com.knowledge.business.service.impl.VectorSearchService;
import com.knowledge.business.service.impl.VectorStorageService;
import com.knowledge.common.AliyunOssUploadUtils;
import com.knowledge.common.annotation.Anonymous;
import com.knowledge.common.annotation.Log;
import com.knowledge.common.config.RuoYiConfig;
import com.knowledge.common.constant.Constants;
import com.knowledge.common.core.controller.BaseController;
import com.knowledge.common.core.domain.AjaxResult;
import com.knowledge.common.core.domain.entity.SysDictData;
import com.knowledge.common.core.domain.entity.SysUser;
import com.knowledge.common.core.domain.model.LoginBody;
import com.knowledge.common.core.page.TableDataInfo;
import com.knowledge.common.enums.BusinessType;
import com.knowledge.common.utils.*;
import com.knowledge.common.utils.file.FileUploadUtils;
import com.knowledge.common.utils.uuid.IdUtils;
import com.knowledge.system.domain.SysConfig;
import com.knowledge.system.service.ISysConfigService;
import com.knowledge.system.service.ISysDictDataService;
import com.knowledge.system.service.ISysUserService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.ImageUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.rmi.ServerException;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 接口
 */
@Log4j2
@RestController
@RequestMapping("/business/web")
public class ApiWebController extends BaseController {

    @Autowired
    VectorSearchService vectorSearchService;

    @Autowired
    VectorStorageService storageService;


    @Autowired
    private ITConfigService tConfigService;


    @Autowired
    private ISysDictDataService iSysDictDataService;


    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ITMemberLevelService tMemberLevelService;


    /**
     * 获取配置信息
     */
    @GetMapping("/nologin/getpzInfo")
    public AjaxResult getpzInfo() {
        TConfig config = new TConfig();
        List<TConfig> tConfigs = tConfigService.selectTConfigList(config);
        return AjaxResult.success(tConfigs);
    }

    /**
     * 查询数据字典
     */
    @GetMapping("/nologin/getDict")
    public AjaxResult getDict(String key) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(key);
        List<SysDictData> dictCache = iSysDictDataService.selectDictDataList(sysDictData);
        return AjaxResult.success(dictCache);
    }

    /**
     * 注销账号
     */
    @PostMapping("/cancelUser")
    public AjaxResult cancelUser() {
        Long userId = SecurityUtils.getUserId();
        sysUserService.deleteUserById(userId);
        return AjaxResult.success();
    }

    /**
     * 个人详细信息
     */
    @GetMapping("/getMyIfnfo")
    public AjaxResult getMyIfnfo() {
        Long userId = SecurityUtils.getUserId();
        System.out.println("用户Id::" + userId);
        SysUser sysUser = sysUserService.selectUserById(userId);
        return AjaxResult.success(sysUser);
    }

    /**
     * 根据用户Id--获取详细信息
     */
    @GetMapping("/getUserInfoById")
    public AjaxResult getUserInfoById(Long userId) {
        SysUser sysUser = sysUserService.selectUserById(userId);
        return AjaxResult.success(sysUser);
    }

    /**
     * 修改头像
     */
    @PostMapping("/updateUser")
    public AjaxResult updateUser(@RequestBody SysUser dto) {
        dto.setUserId(SecurityUtils.getUserId());
        sysUserService.updateUserApp(dto);
        return AjaxResult.success();
    }

    /**
     * 修改手机号
     */
    @PostMapping("/updatePhoneUser")
    public AjaxResult updatePhoneUser(@RequestBody LoginBody dto) {
        if (StringUtils.isEmpty(dto.getPhonenumber())) {
            return AjaxResult.error("手机号不能为空");
        }
        if (StringUtils.isEmpty(dto.getCode())) {
            return AjaxResult.error("验证码不能为空");
        }
        String s = yzCodeUtils.checkRedisKey(dto.getPhonenumber(), dto.getCode());
        if (!StringUtils.isEmpty(s)) {
            return AjaxResult.error(s);
        }
        List<SysUser> sysUsers = sysUserService.selectUserByPhoneAndType(dto.getPhonenumber(), "01");
        if (sysUsers != null && !sysUsers.isEmpty()) {
            return AjaxResult.error("手机号已存在");
        }
        SysUser updateuser = new SysUser();
        updateuser.setUserId(SecurityUtils.getUserId());
        updateuser.setPhonenumber(dto.getPhonenumber());
        sysUserService.updateUserApp(updateuser);
        return AjaxResult.success();
    }


    @Autowired
    private YzCodeUtils yzCodeUtils;

    /**
     * 发送验证码
     */
    @PostMapping("/nologin/sendCode")
    public AjaxResult sendCode(@RequestBody String phone) {
        boolean send = yzCodeUtils.sendPhoneCode(phone);
        return send ? AjaxResult.success() : AjaxResult.error("发送失败");
    }

    /**
     * 会员等级列表
     */
    @GetMapping("/nologin/getLevelList")
    public AjaxResult getLevelList() {
        List<TMemberLevel> tMemberLevels = tMemberLevelService.selectTMemberLevelList(new TMemberLevel());
        return AjaxResult.success(tMemberLevels);
    }

    @Autowired
    private ITQuestionService tQuestionService;

    /**
     * 常见问题列表
     */
    @GetMapping("/getQuestionList")
    public TableDataInfo getQuestionList() {
        List<TQuestion> tQuestions = tQuestionService.selectTQuestionList(new TQuestion());
        return getDataTable(tQuestions);
    }

    /**
     * 常见问题详情
     */
    @GetMapping(value = "/getQuestion/{id}")
    public AjaxResult getQuestion(@PathVariable("id") String id) {
        return AjaxResult.success(tQuestionService.getById(id));
    }

    @Autowired
    private IKnowledgeTypeService knowledgeTypeService;


    @Autowired
    private IKnowledgeDocumentService knowledgeDocumentService;


    /**
     * 数据集列表(分页)
     */
    @GetMapping("/getKnowledgeTypelist")
    public TableDataInfo getKnowledgeTypelist(KnowledgeType knowledgeType) {
        startPage();
        knowledgeType.setUserId(SecurityUtils.getUserIdStr());
        List<KnowledgeType> list = knowledgeTypeService.selectKnowledgeTypeList(knowledgeType);
        for (int i = 0; i < list.size(); i++) {
            KnowledgeType knowledgeType1 = list.get(i);
            String id = knowledgeType1.getId();
            QueryWrapper<KnowledgeDocument> knowledgeDocumentQueryWrapper = new QueryWrapper<>();
            knowledgeDocumentQueryWrapper.eq("type_id", id);
            knowledgeDocumentQueryWrapper.eq("is_folder", "0");
            long count = knowledgeDocumentService.count(knowledgeDocumentQueryWrapper);
            list.get(i).setDocumentNum(count);
        }
        return getDataTable(list);
    }

    /**
     * 数据集列表(不 分页)
     */
    @GetMapping("/getKnowledgeTypeNoPagelist")
    public AjaxResult getKnowledgeTypeNoPagelist(KnowledgeType knowledgeType) {
        if (StringUtils.isNotEmpty(knowledgeType.getIdStr())) {
            knowledgeType.setIds(Arrays.asList(knowledgeType.getIdStr().split(",")));
        }
        knowledgeType.setUserId(SecurityUtils.getUserIdStr());
        List<KnowledgeType> list = knowledgeTypeService.selectKnowledgeTypeList(knowledgeType);
        for (int i = 0; i < list.size(); i++) {
            KnowledgeType knowledgeType1 = list.get(i);
            String id = knowledgeType1.getId();
            QueryWrapper<KnowledgeDocument> knowledgeDocumentQueryWrapper = new QueryWrapper<>();
            knowledgeDocumentQueryWrapper.eq("type_id", id);
            long count = knowledgeDocumentService.count(knowledgeDocumentQueryWrapper);
            list.get(i).setDocumentNum(count);
        }
        return AjaxResult.success(list);
    }


    /**
     * 添加数据集
     */
    @PostMapping("/addKnowledgeType")
    public AjaxResult addKnowledgeType(@Validated @RequestBody KnowledgeType knowledgeType) {
        knowledgeType.setStatus("0");
        knowledgeType.setUserId(SecurityUtils.getUserIdStr());
        knowledgeTypeService.save(knowledgeType);
        return AjaxResult.success();
    }


    @Autowired
    private ITFolderService tFolderService;


    /**
     * 添加文件夹
     */
    @PostMapping("/addFolder")
    public AjaxResult addFolder(@RequestBody TFolder tFolder) {
        KnowledgeDocument tFolder1 = new KnowledgeDocument();
        tFolder1.setFolderId(tFolder.getId());
        tFolder1.setUserId(SecurityUtils.getUserIdStr());
        tFolder1.setDocumentTitle(tFolder.getName());
        tFolder1.setIsFolder("1");
        tFolder1.setTypeId(tFolder.getTypeId());
        knowledgeDocumentService.save(tFolder1);
        return AjaxResult.success();
    }


    /**
     * 查询文件夹列表(分页)
     */
    @GetMapping("/getFolderList")
    public TableDataInfo getFolderList(KnowledgeDocument document) {
        startPage();
        document.setIsGml("1");
        // 查询没有文件夹的文档 和 文件夹
        List<KnowledgeDocument> knowledgeDocuments = knowledgeDocumentService.selectKnowledgeDocumentList(document);
        for (int i = 0; i < knowledgeDocuments.size(); i++) {
            KnowledgeDocument tFolder2 = knowledgeDocuments.get(i);
            String id = tFolder2.getId();
            QueryWrapper<KnowledgeDocument> knowledgeDocumentQueryWrapper = new QueryWrapper<>();
            knowledgeDocumentQueryWrapper.eq("folder_id", id);
            knowledgeDocumentQueryWrapper.eq("is_folder", "0");
            long count = knowledgeDocumentService.count(knowledgeDocumentQueryWrapper);
            knowledgeDocuments.get(i).setDocumentNum(count);
        }
        return getDataTable(knowledgeDocuments);
    }


    @Autowired
    private IKnowledgeDocumentSegmentService knowledgeDocumentSegmentService;

    /**
     * 删除数据集
     */
    @DeleteMapping("/knowledgeType/{ids}")
    @Transactional
    public AjaxResult removeKnowledgeType(@PathVariable String[] ids) {
        knowledgeTypeService.deleteSj(ids);
        // 如果删除的数据集有角色，则删除角色中的数据集 在小智端处理这个逻辑
//        for (int i = 0; i < ids.length; i++) {
//            String id = ids[i];
//            JnSysRole jnSysRole = new JnSysRole();
//            // 数据集(后加)多个用逗号隔开
//            jnSysRole.setDocumentType(id);
//            List<JnSysRole> jnSysRoles = sysRoleService.selectSysRoleList(jnSysRole);
//            for (int j = 0; j < jnSysRoles.size(); j++) {
//                JnSysRole jnSysRoleold = jnSysRoles.get(j);
//                String documentType = jnSysRoleold.getDocumentType();
//                // 修改后
//                List<String> listsplit = new ArrayList<>(Arrays.asList(documentType.split(",")));
//                listsplit.remove(id);
//                String listsplitjoin = listsplit.stream().collect(Collectors.joining(","));
//                jnSysRoleold.setDocumentType(listsplitjoin);
//                sysRoleService.updateSysRoleDocumentType(jnSysRoleold);
//            }
//        }
        return AjaxResult.success();
    }

    /**
     * 删除数据集测试
     */
    @DeleteMapping("/nologin/knowledgeType/{ids}")
    @Transactional
    public AjaxResult testDeleteSjj(@PathVariable String[] ids) {
        // 如果删除的数据集有角色，则删除角色中的数据集
        for (int i = 0; i < ids.length; i++) {
            String id = ids[i];
            JnSysRole jnSysRole = new JnSysRole();
            // 数据集(后加)多个用逗号隔开
            jnSysRole.setDocumentType(id);
            List<JnSysRole> jnSysRoles = sysRoleService.selectSysRoleList(jnSysRole);
            for (int j = 0; j < jnSysRoles.size(); j++) {
                JnSysRole jnSysRoleold = jnSysRoles.get(j);
                String documentType = jnSysRoleold.getDocumentType();
                // 修改后
                List<String> listsplit = new ArrayList<>(Arrays.asList(documentType.split(",")));
                listsplit.remove(id);
                String listsplitjoin = listsplit.stream().collect(Collectors.joining(","));
                jnSysRoleold.setDocumentType(listsplitjoin);
                sysRoleService.updateSysRoleDocumentType(jnSysRoleold);
            }
        }
        return AjaxResult.success();
    }


    /**
     * 查询知识库文档列表(分页)
     */
    @GetMapping("/documentlist")
    public TableDataInfo documentlist(KnowledgeDocument knowledgeDocument) {
        startPage();
        knowledgeDocument.setIsFolder("0");
        List<KnowledgeDocument> list = knowledgeDocumentService.selectKnowledgeDocumentList(knowledgeDocument);
        return getDataTable(list);
    }

    @Autowired
    private DocumentVectorService documentVectorService;

    @Autowired
    private OpenAiService openAiService;

    @Autowired
    private ITCpService cpService;


    /**
     * 修改文件名称
     */
    @PostMapping("/updateDocument")
    @Transactional
    public AjaxResult updateDocument(@RequestBody KnowledgeDocument vo) throws Exception {
        if (StringUtils.isEmpty(vo.getId())) {
            return AjaxResult.error("参数错误");
        }
        KnowledgeDocument byId = knowledgeDocumentService.getById(vo.getId());
        if (byId == null) {
            return AjaxResult.error("参数错误");
        }
        byId.setDocumentTitle(vo.getDocumentTitle());
        knowledgeDocumentService.updateById(byId);
        return AjaxResult.success();
    }

    /**
     * 新增知识库文档
     */
    @PostMapping("/addDocument")
    @Transactional
    public AjaxResult addDocument(@RequestBody KnowledgeDocument vo) throws Exception {
        if(StringUtils.isEmpty(vo.getId())){
            return AjaxResult.error("参数错误");
        }
        // 获取文件路径，解析文件
        vo.setUserId(SecurityUtils.getUserIdStr());
        knowledgeDocumentService.insertKnowledgeDocument(vo);
        String currentUserId = SecurityUtils.getUserIdStr();
        // 异步执行分段和向量化处理
        CompletableFuture.runAsync(() -> {
            try {
                // 等待文档解析完成，最多等待30秒
                int waitCount = 0;
                KnowledgeDocument currentDocument;
                do {
                    Thread.sleep(1000); // 等待1秒
                    currentDocument = knowledgeDocumentService.getById(vo.getId());
                    if (StringUtils.isEmpty(currentDocument.getParseStatus())) {
                        currentDocument.setParseStatus("Processing");
                    }
                    waitCount++;
                    log.info("等待文档 {} ，当前等待次数: {}", vo.getId(), waitCount);

                } while ("Processing".equals(currentDocument.getParseStatus()) && waitCount < 500);
                String documentContent = currentDocument.getDocumentContent();
                if ("Success".equals(currentDocument.getParseStatus()) && StringUtils.isNotEmpty(documentContent)) {
                    log.info("文档 {} 解析完成，开始进行分段处理", vo.getId());
                    try {
                        // 分段处理
                        knowledgeDocumentSegmentService.segmentDocumentContent(
                                vo.getId(),
                                vo.getDocumentType(),
                                currentDocument.getDocumentContent()
                        );
                        // 向量化处理
                        log.info("开始对文档 {} 进行向量化处理", vo.getId());
                        try {
                            documentVectorService.vectorizeDocumentSegments(vo.getId());
                            log.info("文档 {} 向量化处理完成", vo.getId());
                        } catch (Exception vectorException) {
                            log.error("文档 {} 向量化处理失败: {}", vo.getId(), vectorException.getMessage(), vectorException);
                        }
                    } catch (Exception segmentException) {
                        log.error("文档 {} 分段处理失败: {}", vo.getId(), segmentException.getMessage(), segmentException);
                    }
                } else {
                    log.error("文档 {} 解析失败或超时，状态: {}，内容是否为空: {}",
                            vo.getId(),
                            currentDocument.getParseStatus(),
                            StringUtils.isEmpty(documentContent));

                    // 构建更详细的失败原因
                    StringBuilder errorMsg = new StringBuilder("文档解析失败: ");
                    if ("Fail".equals(currentDocument.getParseStatus())) {
                        errorMsg.append("解析过程出错：" + currentDocument.getParseMsg());
                    } else if (waitCount >= 500) {
                        errorMsg.append("解析超时");
                    } else if (StringUtils.isEmpty(documentContent)) {
                        errorMsg.append("解析内容为空");
                    } else {
                        errorMsg.append("未知错误");
                    }
                    currentDocument.setParseStatus("Failed");
                    // 添加详细的失败原因
                    currentDocument.setParseMsg(errorMsg.toString());
                    knowledgeDocumentService.updateById(currentDocument);
                }

            } catch (Exception e) {
                log.error("文档 {} 分段或向量化处理失败: {}", vo.getId(), e.getMessage(), e);
            }
            if (StringUtils.isNotEmpty(vo.getDocumentContent())) {
                CompletableFuture.runAsync(() -> {
                    // 提取产品信息
                    String chatReply = openAiService.getChatCpReply(vo.getDocumentContent());
                    if (!StringUtils.isEmpty(chatReply) && !"未获取到产品名称".equals(chatReply)) {
                        String[] relist = StringUtils.split(chatReply, "$");

                        List<TCp> listsave = new ArrayList<TCp>();
                        for (int i = 0; i < relist.length; i++) {
                            TCp tCp = new TCp();
                            tCp.setId(UUID.randomUUID().toString());
                            tCp.setName(relist[i]);
                            tCp.setUserId(currentUserId);
                            tCp.setDocumentId(vo.getId());
                            cpService.insertTCp(tCp);
                        }
                    }
                });
            }


        });
//        // (1)获取文件路径，解析文件
//        KnowledgeDocument knowledgeDocument = knowledgeDocumentService.insertKnowledgeDocument(vo);
//        String documentContent = knowledgeDocument.getDocumentContent();
//        if (StringUtils.isEmpty(documentContent)) {
//            return AjaxResult.error("文档内容为空");
//        }
//        //（2） 分段
//        knowledgeDocumentSegmentService.segmentDocumentContent(knowledgeDocument.getId(), documentContent);
//        // 异步执行向量化处理
//        CompletableFuture.runAsync(() -> {
//            try {
//                logger.info("开始对文档 {} 进行向量化处理", knowledgeDocument.getId());
//                documentVectorService.vectorizeDocumentSegments(knowledgeDocument.getId());
//                logger.info("文档 {} 向量化处理完成", knowledgeDocument.getId());
//            } catch (Exception e) {
//                logger.error("文档 {} 向量化处理失败: {}", knowledgeDocument.getId(), e.getMessage(), e);
//            }
//        });
//        // 提取产品信息
//        String chatReply = openAiService.getChatReply(vo.getDocumentContent());
        //
        return AjaxResult.success();
    }

    /**
     * 补充知识文档-根据问题生成一个txt文件，文件的名称 就是问题
     */
    @PostMapping("/addDocumentBz")
    @Transactional
    public AjaxResult addDocumentBz(@RequestBody KnowledgeDocument vo) throws Exception {
        // 知识库Id
        String typeId = vo.getTypeId();
        if (StringUtils.isEmpty(typeId)) {
            return AjaxResult.error("获取知识库Id 失败");
        }
        // 问题
        String question = vo.getQuestion();
        if (StringUtils.isEmpty(question)) {
            return AjaxResult.error("获取问题失败");
        }
        // 问题答案
        String documentContent = vo.getDocumentContent();
        if (StringUtils.isEmpty(documentContent)) {
            return AjaxResult.error("获取问题答案失败");
        }
        vo.setDocumentTitle(question);
        vo.setFileType("txt");
        vo.setDocumentType("1");
        vo.setUserId(SecurityUtils.getUserIdStr());
        vo.setIsFolder("0");
        knowledgeDocumentService.save(vo);
        try {
            // 分段处理
            knowledgeDocumentSegmentService.segmentDocumentContent(
                    vo.getId(),
                    vo.getDocumentType(),
                    vo.getDocumentContent()
            );
            // 向量化处理
            log.info("开始对文档 {} 进行向量化处理", vo.getId());
            try {
                documentVectorService.vectorizeDocumentSegments(vo.getId());
                log.info("文档 {} 向量化处理完成", vo.getId());
            } catch (Exception vectorException) {
                log.error("文档 {} 向量化处理失败: {}", vo.getId(), vectorException.getMessage(), vectorException);
            }
        } catch (Exception segmentException) {
            log.error("文档 {} 分段处理失败: {}", vo.getId(), segmentException.getMessage(), segmentException);
        }
        return AjaxResult.success();

    }

    @Autowired
    AliyunOssUploadUtils aliyunOssUploadUtils;

    /**
     * 删除知识库文档
     */
    //
    @Log(title = "知识库文档", businessType = BusinessType.DELETE)
    @DeleteMapping("/document/{ids}")
    public AjaxResult removedocument(@PathVariable String[] ids) {
        knowledgeDocumentService.deleteSj(ids);
        return AjaxResult.success();
    }


    @Autowired
    private JnISysRoleService sysRoleService;

    /**
     * 查询锦囊或在线渠道列表(分页)
     */
    @GetMapping("/JnSysRolelist")
    public TableDataInfo JnSysRolelist(JnSysRole sysRole) {
        startPage();
        sysRole.setUserId(SecurityUtils.getUserId());
        List<JnSysRole> list = sysRoleService.selectSysRoleList(sysRole);
        return getDataTable(list);
    }

    /**
     * 添加锦囊
     */
    @PostMapping("/addJnSysRole")
    public AjaxResult addJnSysRole(@Validated @RequestBody JnSysRole sysRole) {
        sysRole.setUserId(SecurityUtils.getUserId());
        //启用
        sysRole.setState("1");
        sysRole.setCreateBy(SecurityUtils.getUserIdStr());
        sysRole.setCreateTime(DateUtils.getNowDate());
        // 固定
        sysRole.setTtsId("3");
        sysRole.setSttId("2");
        sysRole.setModelId("1");
        sysRoleService.insertSysRole(sysRole);
        return AjaxResult.success();
    }

    /**
     * 编辑锦囊
     */
    @PutMapping("/ediTJnSysRole")
    public AjaxResult ediTJnSysRole(@Validated @RequestBody JnSysRole sysRole) {
        sysRoleService.updateSysRole(sysRole);
        return AjaxResult.success();
    }


    /**
     * 获取锦囊管理详细信息
     */
    @Anonymous
    @GetMapping(value = "/JnSysRoleDetail/{roleId}")
    public AjaxResult JnSysRoleDetail(@PathVariable("roleId") String roleId) {
        return AjaxResult.success(sysRoleService.selectSysRoleByRoleId(roleId));
    }

    /**
     * 删除锦囊
     */
    @DeleteMapping("/deleteTJnSysRole/{configIds}")
    public AjaxResult deleteTJnSysRole(@PathVariable String configIds) {
        return toAjax(sysRoleService.deleteSysRoleByRoleId(configIds));
    }


    /**
     * 测试发音
     */
    @GetMapping("/nologin/testVoice")
    @ResponseBody
    public AjaxResult testAudio(
            String message,
            String voiceName,
            int speechRate,
            int pitchRate
    ) {
        try {
            String outpath = RuoYiConfig.getUploadPath();
            AliyunTtsNewService aliyunTtsNewService = new AliyunTtsNewService(voiceName, speechRate, pitchRate, outpath + "/");
            String audioFilePath = aliyunTtsNewService.ttsWithNls(message);
            System.out.println("文件的真实路径：" + audioFilePath);
            String pathFileName = FileUtil.getName(audioFilePath);
            String url = Constants.RESOURCE_PREFIX + "/upload/" + pathFileName;
            AjaxResult result = AjaxResult.success();
            result.put("data", url);
            return result;
        } catch (IndexOutOfBoundsException e) {
            return AjaxResult.error("请先到语音合成配置页面配置对应Key");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return AjaxResult.error();
        }
    }


    @Autowired
    private LllmISysConfigService sysConfigService;


    /**
     * 查询模型配置(模型、语音识别、语音合成等)列表
     */
    @GetMapping("/lllmSysConfiglist")
    public AjaxResult lllmSysConfiglist(LllmSysConfig lllmSysConfig) {
        List<LllmSysConfig> list = sysConfigService.selectSysConfigList(lllmSysConfig);
        return AjaxResult.success(list);
    }


    @Autowired
    private ISysDeviceService sysDeviceService;

    /**
     * 查询设备信息列表
     */
    @GetMapping("/getSysDevicelist")
    public AjaxResult getSysDevicelist(SysDevice sysDevice) {
        sysDevice.setUserId(SecurityUtils.getUserId());
        List<SysDevice> list = sysDeviceService.selectSysDeviceList(sysDevice);
        // 按设备类型分组
        Map<String, List<SysDevice>> groupedByType = list.stream()
                .collect(Collectors.groupingBy(SysDevice::getType));
        return AjaxResult.success(groupedByType);
    }


    @Autowired
    private ISysConfigService configService;


    /**
     * 下载在线渠道二维码
     */
    /**
     * 下载在线渠道二维码
     */
    @PostMapping("/downloadQrQdcode")
    public void downloadQrQdcode(JnSysRole vo, HttpServletResponse response) throws IOException {
        TConfig config =new TConfig();
        config.setConfigKey("websiteH5");
        List<TConfig>  list  =   tConfigService.selectTConfigList(config);
        String  ewmurl="";
        if(StringUtils.isNotEmpty( list)){
            TConfig config1 = list.get(0);
            ewmurl=config1.getConfigValue();
        }
        String url = ewmurl + "?roleId=" + vo.getRoleId();

        // 创建更大的二维码图片，为文字留出空间
        BufferedImage originalImage = QrCodeUtils.buildQrCodeImage(url);
        // 创建新的图片，高度增加以容纳文字
        int newWidth = originalImage.getWidth();
        int newHeight = originalImage.getHeight() + 30; // 增加30像素用于显示文字
        BufferedImage bufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);

        // 填充白色背景
        Graphics2D g2d = bufferedImage.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, newWidth, newHeight);

        // 绘制原始二维码到新图片的上部
        g2d.drawImage(originalImage, 0, 0, null);
        g2d.dispose();

        // 获取角色名称
        String roleName = vo.getRoleName();
        // 在图片上添加角色名称
        if (StringUtils.isNotEmpty(vo.getRoleName())) {
            Graphics2D graphics = bufferedImage.createGraphics();
            // 设置字体和颜色，使用支持中文的字体
            graphics.setFont(new Font("微软雅黑", Font.BOLD, 16));
            graphics.setColor(Color.BLACK);
            // 计算文字位置（居中显示在图片底部新增的空间中）
            FontMetrics fontMetrics = graphics.getFontMetrics();
            int stringWidth = fontMetrics.stringWidth(roleName);
            int x = (bufferedImage.getWidth() - stringWidth) / 2;
            // 将文字放置在新增的底部空间中
            int y = bufferedImage.getHeight() - 10; // 距离底部10像素
            // 绘制文字
            graphics.drawString(roleName, x, y);
            graphics.dispose();
        }

        response.setContentType("image/png");

        // 对文件名进行URL编码以避免HTTP头编码问题
        String fileName = StringUtils.isNotEmpty(roleName) ? roleName + "_qrcode.png" : "qrcode.png";
        String encodedFileName = java.net.URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
        ImageIO.write(bufferedImage, "png", response.getOutputStream());
    }


    /**
     * 下载在线渠道二维码(返回base64)
     */
    @PostMapping("/downloadQrQdcodeBase")
    public AjaxResult downloadQrQdcodeBase(JnSysRole vo, HttpServletResponse response) throws IOException {
        String ewmurl = configService.selectConfigByKey("ewmurl");
        String url = ewmurl + "?roleId=" + vo.getRoleId();
        BufferedImage bufferedImage = QrCodeUtils.buildQrCodeImage(url);
        // 返回base64

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", outputStream);
        String base64Image = Base64.getEncoder().encodeToString(outputStream.toByteArray());
        HashMap<String, Object> map = new HashMap<>();
        map.put("qrcode", base64Image);
        return AjaxResult.success(map);

    }

    /**
     * 查询消息列表
     */
    @Anonymous
    @GetMapping("/getSysMessagelist")
    public TableDataInfo getSysMessagelist(SysMessage sysMessage) {
        // 1 设备  2 web
        String type = sysMessage.getType();
        List<SysMessage> sysMessages = new ArrayList<>();
        String userId = sysMessage.getUserId();
        if (StringUtils.isNotEmpty(userId)) {
            // 查询角色
            JnSysRole jnSysRole = new JnSysRole();
            jnSysRole.setUserId(Long.valueOf(userId));
            List<JnSysRole> jnSysRoles = sysRoleService.selectSysRoleList(jnSysRole);
            // 获取角色Id 的集合
            List<String> roleIds = jnSysRoles.stream().map(JnSysRole::getRoleId).collect(Collectors.toList());
            sysMessage.setRoleList(roleIds);
        } else {
            sysMessage.setRoleList(null);
        }
        if (CollectionUtils.isEmpty(sysMessage.getRoleList())) {
            return getDataTable(sysMessages);
        }
        String isPush = sysMessage.getIsPush();
        if ("1".equals(isPush)) {
            sysMessage.setSender("assistant");
        } else {
            sysMessage.setSender("user");
        }
        if ("2".equals(type)) {
            sysMessage.setDeviceId("SYSTEM_H5_DEVICE");
        } else if ("1".equals(type)) {
            sysMessage.setNoDeviceId("SYSTEM_H5_DEVICE");
        }
        startPage();
        if ("1".equals(isPush)) {
            //主动推动  知识库 按照 回复的知识库名称筛选
            String documentTypeName = sysMessage.getDocumentTypeName();
            if (!StringUtils.isEmpty(documentTypeName)) {
                sysMessage.setReplyDocumentTypeName(documentTypeName);
                sysMessage.setDocumentTypeName("");
            }
        }
        sysMessages = sysMessageService.selectSysMessageList(sysMessage);

        for (int i = 0; i < sysMessages.size(); i++) {
            // 获取对应的回复
            QueryWrapper<SysMessage> queryWrapper = new QueryWrapper<>();
            if ("1".equals(isPush)) {
                queryWrapper.eq("sender", "user");
            } else {
                queryWrapper.eq("sender", "assistant");
            }
            queryWrapper.eq("state", "1");
            queryWrapper.ge("createTime", sysMessages.get(i).getCreateTime());
            queryWrapper.eq("sessionId", sysMessages.get(i).getSessionId());
            queryWrapper.orderByAsc("createTime");
            queryWrapper.last("limit 1");
            List<SysMessage> assistantMessages = sysMessageService.list(queryWrapper);
            if (!CollectionUtils.isEmpty(assistantMessages)) {
                sysMessages.get(i).setReply(assistantMessages.get(0));
            }
        }
        return getDataTable(sysMessages);
    }


    /**
     * 导出推送消息列表
     */
    @Anonymous
    @GetMapping("/exportSysMessage")
    public void exportSysMessage(SysMessage sysMessage, String messageIds, HttpServletResponse response) throws IOException {
        // 设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=sys_messages.xlsx");
        List<SysMessage> sysMessages = new ArrayList<>();
        String userId = sysMessage.getUserId();
        if (StringUtils.isNotEmpty(userId)) {
            // 查询角色
            JnSysRole jnSysRole = new JnSysRole();
            jnSysRole.setUserId(Long.valueOf(userId));
            List<JnSysRole> jnSysRoles = sysRoleService.selectSysRoleList(jnSysRole);
            // 获取角色Id 的集合
            List<String> roleIds = jnSysRoles.stream().map(JnSysRole::getRoleId).collect(Collectors.toList());
            sysMessage.setRoleList(roleIds);
        } else {
            sysMessage.setRoleList(null);
        }
        if (CollectionUtils.isEmpty(sysMessage.getRoleList())) {
            // 如果没有角色列表，则导出空表格
            writeMessagesToExcel(new ArrayList<>(), response);
            return;
        }
        String isPush = sysMessage.getIsPush();
        if ("1".equals(isPush)) {
            sysMessage.setSender("assistant");
        } else {
            sysMessage.setSender("user");
        }
        // 如果提供了messageIds，则只导出这些消息
        if (StringUtils.isNotEmpty(messageIds)) {
            List<String> messageIdList = Arrays.asList(messageIds.split(","));
            sysMessages = sysMessageService.list(new QueryWrapper<SysMessage>()
                    .in("messageId", messageIdList)
                    .eq("isPush", isPush)
                    .orderByDesc("createTime"));
        } else {
            // 否则导出所有符合条件的消息
            sysMessages = sysMessageService.selectSysMessageList(sysMessage);
        }
        List<SysMessage> exMessages = new ArrayList<>();
        for (int i = 0; i < sysMessages.size(); i++) {
            exMessages.add(sysMessages.get(i));
            // 获取对应的回复
            QueryWrapper<SysMessage> queryWrapper = new QueryWrapper<>();
            if ("1".equals(isPush)) {
                queryWrapper.eq("sender", "user");
            } else {
                queryWrapper.eq("sender", "assistant");
            }
            queryWrapper.eq("state", "1");
            queryWrapper.ge("createTime", sysMessages.get(i).getCreateTime());
            queryWrapper.eq("sessionId", sysMessages.get(i).getSessionId());
            queryWrapper.orderByAsc("createTime");
            queryWrapper.last("limit 1");
            List<SysMessage> assistantMessages = sysMessageService.list(queryWrapper);
            if (!CollectionUtils.isEmpty(assistantMessages)) {
                sysMessages.get(i).setReply(assistantMessages.get(0));
                exMessages.add(assistantMessages.get(0));
            }
        }
        writeMessagesToExcel(exMessages, response);
    }

    private void writeMessagesToExcel(List<SysMessage> messages, HttpServletResponse response) throws IOException {
        // 创建工作簿
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("消息列表");

        // 创建表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("消息内容");
        headerRow.createCell(1).setCellValue("设备名称");
        headerRow.createCell(2).setCellValue("数据集");
        headerRow.createCell(4).setCellValue("时间");
        // 填充数据
        for (int i = 0; i < messages.size(); i++) {
            SysMessage msg = messages.get(i);
            String isPush = msg.getIsPush();
            Row row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(msg.getMessage());
            if ("1".equals(isPush)) {
                row.createCell(1).setCellValue("");
                row.createCell(2).setCellValue("");
            } else {
                row.createCell(1).setCellValue(msg.getDeviceName());
                row.createCell(2).setCellValue(msg.getDocumentTypeName());
            }
            row.createCell(4).setCellValue(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", msg.getCreateTime()));

//            SysMessage reply = msg.getReply();
//            if (reply != null) {
//                row.createCell(5).setCellValue(reply.getMessage());
//            }
//            row.createCell(6).setCellValue(msg.getDeviceName());
        }
        // 调整列宽
        for (int i = 0; i < 8; i++) {
            sheet.autoSizeColumn(i);
        }
        // 写入响应流
        workbook.write(response.getOutputStream());
        workbook.close();
    }


    @Autowired
    private IMessageStatService messageStatService;


    /**
     * 获取热门消息统计（基于相似度分析）
     */
    @GetMapping("/nologin/hot-similarity")
    public AjaxResult getHotMessagesBySimilarity(
            FxDTO dto) {
        String dzStatus = dto.getDzStatus();
        if (StringUtils.isEmpty(dto.getUserId())) {
            return AjaxResult.success();
        }
        this.setFxtj(dto);
        // 小程序传入用户Id
        if (CollectionUtils.isEmpty(dto.getRoleList()) && StringUtils.isNotEmpty(dto.getUserId())) {
            return AjaxResult.success();
        }
        PageUtils.startPage();
        List<SysMessage> sysMessages = null;
        if (StringUtils.isEmpty(dzStatus)) {
            sysMessages = sysMessageService.selectMessagesHot(dto);
        } else {
            sysMessages = sysMessageService.selectMessagesWithTimeByDays(dto);
        }
        return AjaxResult.success(sysMessages);
    }


    /**
     * 获取热门消息统计H5
     */
    @GetMapping("/nologin/hot-similarityH5")
    public AjaxResult hotSimilarityH5(
            FxDTO dto) {
        if (StringUtils.isEmpty(dto.getRoleId())) {
            return AjaxResult.success();
        }
        this.setFxtjH5(dto);
        // h5传入角色Id
        if (CollectionUtils.isEmpty(dto.getTypeList()) && StringUtils.isNotEmpty(dto.getRoleId())) {
            return AjaxResult.success();
        }
        PageUtils.startPage();
        List<SysMessage> sysMessages = null;
        sysMessages = sysMessageService.selectMessagesHot(dto);
        return AjaxResult.success(sysMessages);
    }


    /**
     * 获取热门消息统计（基于相似度分析）分页
     */
    @GetMapping("/nologin/hot-similarityPage")
    public TableDataInfo gehotSimilarityPage(
            FxDTO dto) {
        String dzStatus = dto.getDzStatus();
        if (StringUtils.isEmpty(dto.getUserId())) {
            return getDataTable(new ArrayList<>());
        }
        this.setFxtj(dto);
        // 小程序传入用户Id
        if (CollectionUtils.isEmpty(dto.getRoleList()) && StringUtils.isNotEmpty(dto.getUserId())) {
            return getDataTable(new ArrayList<>());
        }
        PageUtils.startPage();
        List<SysMessage> sysMessages = null;
        if (StringUtils.isEmpty(dzStatus)) {
            sysMessages = sysMessageService.selectMessagesHot(dto);
        } else {
            sysMessages = sysMessageService.selectMessagesWithTimeByDays(dto);
        }
        return getDataTable(sysMessages);
    }

    /**
     * 导出答中 未答中 消息统计
     */
//    @GetMapping("/exportDzMessages")
//    public void exportDzMessages(FxDTO dto,
//                                 HttpServletResponse response) throws IOException {
//        String dzStatus = dto.getDzStatus();
//        this.setFxtj(dto);
////        PageUtils.startPage();
//        List<SysMessage> sysMessages = null;
//        sysMessages = sysMessageService.selectMessagesWithTimeByDays(dto);
//        // 设置响应头
//        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//        response.setCharacterEncoding("utf-8");
//        response.setHeader("Content-Disposition", "attachment; filename=hot_messages_statistics.xlsx");
//
//        // 创建工作簿
//        Workbook workbook = new XSSFWorkbook();
//        Sheet sheet = workbook.createSheet("热门消息统计");
//
//        // 创建表头
//        Row headerRow = sheet.createRow(0);
//        headerRow.createCell(0).setCellValue("消息内容");
//        headerRow.createCell(1).setCellValue("出现次数");
//        // 设备名称
//        headerRow.createCell(2).setCellValue("设备名称");
//        // 知识库名称
//        headerRow.createCell(3).setCellValue("知识库名称");
//
////        headerRow.createCell(2).setCellValue("相似度");
////        headerRow.createCell(3).setCellValue("点赞数");
////        headerRow.createCell(4).setCellValue("点踩数");
////        headerRow.createCell(5).setCellValue("最近出现时间");
//        // 填充数据
//        if (sysMessages != null && !sysMessages.isEmpty()) {
//            for (int i = 0; i < sysMessages.size(); i++) {
//                SysMessage message = sysMessages.get(i);
//                Row row = sheet.createRow(i + 1);
//                row.createCell(0).setCellValue(message.getMessage());
//                row.createCell(1).setCellValue(message.getCount());
//                row.createCell(2).setCellValue(message.getDeviceName());
//                row.createCell(3).setCellValue(message.getDocumentTypeName());
//            }
//        }
//        // 调整列宽
//        for (int i = 0; i < 4; i++) {
//            sheet.autoSizeColumn(i);
//        }
//        // 写入响应流
//        workbook.write(response.getOutputStream());
//        workbook.close();
//    }


    @Autowired
    private ISysMessageService sysMessageService;

    @Autowired
    private ITKeywordsService keywordsService;


    /**
     * 统计关键词
     */
    @GetMapping("/nologin/keywordTj")
    public AjaxResult keywordTj(FxDTO dto) {
        if (StringUtils.isEmpty(dto.getUserId())) {
            return AjaxResult.success();
        }
        this.setFxtj(dto);
        List<TKeywords> tKeywords = new ArrayList<>();
        if (CollectionUtils.isEmpty(dto.getRoleList())) {
            return AjaxResult.success(tKeywords);
        }
        startPage();
        tKeywords = keywordsService.selectTKeywordsTjList(dto);
        return AjaxResult.success(tKeywords);
    }

    /**
     * 消息时段分析折线图分析
     */
    @GetMapping("/nologin/sjfx")
    public AjaxResult sjfx(FxDTO dto) {
        // 按照上面的时间段查询（SysMessage） 对应时间的数量，生成折线图数据
        if (StringUtils.isEmpty(dto.getUserId())) {
            return AjaxResult.success();
        }
        this.setFxtj(dto);
        if (CollectionUtils.isEmpty(dto.getRoleList())) {
            return AjaxResult.success();
        }
        startPage();
        List<Map<String, Object>> result = messageStatService.getMessageCountByTimePeriod(dto);
        return AjaxResult.success(result);
    }


    @Autowired
    private ITCpRecordService tCpRecordService;

    /**
     * 销售分析
     */
    @GetMapping("/nologin/getCpRecordTj")
    public TableDataInfo getCpRecordTj(
            FxDTO dto) {
        if (StringUtils.isEmpty(dto.getUserId())) {
            return getDataTable(new ArrayList<>());
        }
        this.setFxtj(dto);
        startPage();
        List<Map<String, Object>> result = tCpRecordService.selectTCpRecordStatistics(dto);
        return getDataTable(result);
    }

    /**
     * 销售分析柱状图数据
     */
    @GetMapping("/nologin/getCpRecordTjChart")
    public AjaxResult getCpRecordTjChart(FxDTO dto) {
        if (StringUtils.isEmpty(dto.getUserId())) {
            return AjaxResult.success();
        }
        HashMap<String, Object> map = new HashMap<>();
        this.setFxtj(dto);
        List<JSONObject> jsonList = new ArrayList<>();
        List<Map<String, Object>> result = tCpRecordService.selectTCpRecordStatistics(dto);
        for (int i = 0; i < result.size(); i++) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", result.get(i).get("name"));
            jsonObject.put("count", result.get(i).get("count"));
            jsonList.add(jsonObject);
        }
        if (!CollectionUtils.isEmpty(jsonList)) {
            String chatReply = openAiService.getChatReply(jsonList.toString());
            System.out.println(chatReply);
            map.put("chatReply", chatReply);
        }
        System.out.println(jsonList);
        map.put("result", result);
        return AjaxResult.success(map);
    }


    /**
     * 多种类型导出数据
     */
    @GetMapping("/exportHzTj")
    public void exportHzTj(FxDTO dto, HttpServletResponse response) throws IOException {
        // 1 来源  2 热门问题 3 未带中问题  4 关键词  5 时段分析 6   销售分析 7  售后分析
        // 导出的类型 逗号隔开，不同的类型创建不同的sheet页面
        String exportType = dto.getExportType();
        String userId = dto.getUserId();
        if (StringUtils.isEmpty(exportType)) {
            throw new RuntimeException("请选择导出类型");
        }
        if (StringUtils.isEmpty(userId)) {
            throw new RuntimeException("请选择用户");
        }
        this.setFxtj(dto);
        // 设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=statistics_data.xlsx");

        String[] exportTypes = exportType.split(",");

        // 创建工作簿
        Workbook workbook = new XSSFWorkbook();

        try {
            for (int i = 0; i < exportTypes.length; i++) {
                String type = exportTypes[i].trim();
                switch (type) {
                    case "1":
                        // 来源分布
                        createPieChartSheet(workbook, "来源分布", dto);
                        break;
                    case "2":
                        // 热门问题
                        createHotQuestionsSheet(workbook, "热门问题", dto);
                        break;
                    case "3":
                        // 未答中问题
                        createUnansweredQuestionsSheet(workbook, "未答中问题", dto);
                        break;
                    case "4":
                        // 关键词
                        createKeywordsSheet(workbook, "关键词统计", dto);
                        break;
                    case "5":
                        // 时段分析
                        createTimePeriodSheet(workbook, "时段分析", dto);
                        break;
                    case "6":
                        // 销售分析
                        createSalesAnalysisSheet(workbook, "销售分析", dto);
                        break;
                    case "7":
                        // 售后分析
                        createAfterSalesSheet(workbook, "售后分析", dto);
                        break;
                    default:
                        break;
                }
            }

            // 写入响应流
            workbook.write(response.getOutputStream());
        } finally {
            workbook.close();
        }
    }

    /**
     * 创建来源分布sheet
     */
    private void createPieChartSheet(Workbook workbook, String sheetName, FxDTO dto) {
        Sheet sheet = workbook.createSheet(sheetName);

        // 表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("来源类型");
        headerRow.createCell(1).setCellValue("数量");
        headerRow.createCell(2).setCellValue("占比(%)");

        try {
            // 获取来源分布数据
            AjaxResult result = getPieChartData(dto);
            if (result != null && result.get("data") != null) {
                List<Map<String, Object>> pieData = (List<Map<String, Object>>) result.get("data");
                for (int i = 0; i < pieData.size(); i++) {
                    Map<String, Object> data = pieData.get(i);
                    Row row = sheet.createRow(i + 1);
                    row.createCell(0).setCellValue((String) data.get("name"));
                    row.createCell(1).setCellValue(((Number) data.get("value")).longValue());
                    row.createCell(2).setCellValue((data.get("percent") + ""));
                }
            }
        } catch (Exception e) {
            logger.error("导出来源分布数据失败", e);
        }

        // 调整列宽
        for (int i = 0; i < 3; i++) {
            sheet.autoSizeColumn(i);
        }
    }

    /**
     * 创建热门问题sheet
     */
    private void createHotQuestionsSheet(Workbook workbook, String sheetName, FxDTO dto) {
        Sheet sheet = workbook.createSheet(sheetName);
        // 表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("消息内容");
        headerRow.createCell(1).setCellValue("出现次数");

        try {
            if (!CollectionUtils.isEmpty(dto.getRoleList())) {
                // 获取热门问题数据
                List<SysMessage> hotMessages = sysMessageService.selectMessagesHot(dto);
                if (hotMessages != null && !hotMessages.isEmpty()) {
                    for (int i = 0; i < hotMessages.size(); i++) {
                        SysMessage message = hotMessages.get(i);
                        Row row = sheet.createRow(i + 1);
                        row.createCell(0).setCellValue(message.getMessage());
                        row.createCell(1).setCellValue(message.getCount());
                    }
                }

            }

        } catch (Exception e) {
            logger.error("导出热门问题数据失败", e);
        }

        // 调整列宽
        for (int i = 0; i < 4; i++) {
            sheet.autoSizeColumn(i);
        }
    }

    /**
     * 创建未答中问题sheet
     */
    private void createUnansweredQuestionsSheet(Workbook workbook, String sheetName, FxDTO dto) {
        Sheet sheet = workbook.createSheet(sheetName);

        // 表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("消息内容");
        headerRow.createCell(1).setCellValue("出现次数");
        headerRow.createCell(2).setCellValue("设备名称");
        headerRow.createCell(3).setCellValue("知识库名称");

        try {
            dto.setDzStatus("0");
            List<String> roleList = dto.getRoleList();
            if (!CollectionUtils.isEmpty(roleList)) {
                List<SysMessage> unansweredMessages = sysMessageService.selectMessagesWithTimeByDays(dto);
                if (unansweredMessages != null && !unansweredMessages.isEmpty()) {
                    for (int i = 0; i < unansweredMessages.size(); i++) {
                        SysMessage message = unansweredMessages.get(i);
                        Row row = sheet.createRow(i + 1);
                        row.createCell(0).setCellValue(message.getMessage());
                        row.createCell(1).setCellValue(message.getCount());
                        row.createCell(2).setCellValue(message.getDeviceName());
                        row.createCell(3).setCellValue(message.getDocumentTypeName());
                    }
                }
            }

        } catch (Exception e) {
            logger.error("导出未答中问题数据失败", e);
        }
        // 调整列宽
        for (int i = 0; i < 4; i++) {
            sheet.autoSizeColumn(i);
        }
    }

    /**
     * 创建关键词sheet
     */
    private void createKeywordsSheet(Workbook workbook, String sheetName, FxDTO dto) {
        Sheet sheet = workbook.createSheet(sheetName);
        // 表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("关键词");
        try {
            if (!CollectionUtils.isEmpty(dto.getRoleList())) {
                // 获取关键词数据
                List<TKeywords> keywords = keywordsService.selectTKeywordsTjList(dto);
                if (keywords != null && !keywords.isEmpty()) {
                    for (int i = 0; i < keywords.size(); i++) {
                        TKeywords keyword = keywords.get(i);
                        Row row = sheet.createRow(i + 1);
                        row.createCell(0).setCellValue(keyword.getKeyWord());
                    }
                }
            }
        } catch (Exception e) {
            logger.error("导出关键词数据失败", e);
        }

        // 调整列宽
        sheet.autoSizeColumn(0);
    }

    /**
     * 创建时段分析sheet
     */
    private void createTimePeriodSheet(Workbook workbook, String sheetName, FxDTO dto) {
        Sheet sheet = workbook.createSheet(sheetName);

        // 表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("时间段");
        headerRow.createCell(1).setCellValue("消息数量");

        try {
            if (!CollectionUtils.isEmpty(dto.getRoleList())) {
                // 获取时段分析数据
                List<Map<String, Object>> timeData = messageStatService.getMessageCountByTimePeriod(dto);
                if (timeData != null && !timeData.isEmpty()) {
                    for (int i = 0; i < timeData.size(); i++) {
                        Map<String, Object> data = timeData.get(i);
                        Row row = sheet.createRow(i + 1);
                        row.createCell(0).setCellValue((String) data.get("timePeriod"));
                        row.createCell(1).setCellValue(((Number) data.get("count")).longValue());
                    }
                }
            }
        } catch (Exception e) {
            logger.error("导出时段分析数据失败", e);
        }

        // 调整列宽
        for (int i = 0; i < 2; i++) {
            sheet.autoSizeColumn(i);
        }
    }

    /**
     * 创建销售分析sheet
     */
    private void createSalesAnalysisSheet(Workbook workbook, String sheetName, FxDTO dto) {
        Sheet sheet = workbook.createSheet(sheetName);

        // 表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("产品名称");
        headerRow.createCell(1).setCellValue("数量");

        try {
            AjaxResult result = getCpRecordTjChart(dto);

            if (result != null && result.get("data") != null) {
                List<Map<String, Object>> pieData = (List<Map<String, Object>>) result.get("result");
                int k = 0;
                for (int i = 0; i < pieData.size(); i++) {
                    Map<String, Object> data = pieData.get(i);
                    Row row = sheet.createRow(i + 1);
                    row.createCell(0).setCellValue(data.get("name") != null ? data.get("name").toString() : "");
                    row.createCell(1).setCellValue(data.get("count") + "");
                    k++;
                }
                Object chatReply = result.get("chatReply");
                Row headerRow1 = sheet.createRow(k + 1);
                // 分析建议
                if (chatReply != null) {
                    headerRow1.createCell(0).setCellValue(chatReply == null ? "" : chatReply.toString());
                }

            }
        } catch (Exception e) {
            logger.error("导出销售分析数据失败", e);
        }

        // 调整列宽
        for (int i = 0; i < 2; i++) {
            sheet.autoSizeColumn(i);
        }
    }

    /**
     * 创建售后分析sheet
     */
    private void createAfterSalesSheet(Workbook workbook, String sheetName, FxDTO dto) {
        Sheet sheet = workbook.createSheet(sheetName);

        // 表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("产品名称");
        headerRow.createCell(1).setCellValue("出现次数");
        List<Map<String, Object>> result = tCpRecordService.selectTCpRecordStatistics(dto);
        for (int i = 0; i < result.size(); i++) {
            Row row = sheet.createRow(i + 1);
            Map<String, Object> data = result.get(i);
            row.createCell(0).setCellValue(data.get("name") != null ? data.get("name").toString() : "");
            row.createCell(1).setCellValue(data.get("count") + "");

        }
        // 调整列宽
        for (int i = 0; i < 2; i++) {
            sheet.autoSizeColumn(i);
        }
    }


    @Autowired
    private ITProductTypeService tProductTypeService;

    /**
     * 查询产品分类列表
     */
    @GetMapping("/tProductTypeList")
    public AjaxResult tProductTypeList(TProductType tProductType) {
        List<TProductType> list = tProductTypeService.selectTProductTypeList(tProductType);
        return AjaxResult.success(list);
    }


    @Autowired
    private ITProductService tProductService;

    /**
     * 查询产品信息列表(分页)
     */
    @GetMapping("/tProductlist")
    public TableDataInfo tProductlist(TProduct tProduct) {
        startPage();
        tProduct.setStatus("Y");
        List<TProduct> list = tProductService.selectTProductList(tProduct);
        return getDataTable(list);
    }

    /**
     * 查询产品详情
     */
    @GetMapping(value = "/tProductDetail/{id}")
    public AjaxResult tProductDetail(@PathVariable("id") String id) {
        TProduct byId = tProductService.getById(id);
        return AjaxResult.success(byId);
    }


    @Autowired
    private ITLbImageService tLbImageService;

    /**
     * 查询轮播图管理列表
     */
    @GetMapping("/tLbImagelist")
    @Anonymous
    public AjaxResult tLbImagelist(TLbImage tLbImage) {
        List<TLbImage> list = tLbImageService.selectTLbImageList(tLbImage);
        return AjaxResult.success(list);
    }

    @Autowired
    private ITYqRecordService tYqRecordService;


    /**
     * 查询邀请信息列表(分页)
     */
    @GetMapping("/tYqRecordlist")
    public TableDataInfo tYqRecordlist() {
        startPage();
        TYqRecord tYqRecord = new TYqRecord();
        tYqRecord.setUserId(SecurityUtils.getUserIdStr());
        List<TYqRecord> list = tYqRecordService.selectTYqRecordList(tYqRecord);
        return getDataTable(list);
    }


    /**
     * 保存邀请信息
     */
    @PostMapping("/addtYqRecord")
    public AjaxResult addtYqRecord(@RequestBody TYqRecord tYqRecord) {
        tYqRecord.setUserId(SecurityUtils.getUserIdStr());
        return toAjax(tYqRecordService.save(tYqRecord));
    }

    /**
     * 首页  设备总数数量   在线设备数量  今日对话数量 统计
     */
    @GetMapping("/nologin/getDeviceAndMessageTotal")
    public AjaxResult getDeviceAndMessageTotal(String userId) {
        // 设备总数
        SysDevice sysDevice = new SysDevice();
        if (StringUtils.isNotEmpty(userId)) {
            sysDevice.setUserId(Long.valueOf(userId));
        } else {
            return AjaxResult.success();
        }
        List<SysDevice> list = sysDeviceService.selectSysDeviceList(sysDevice);
        // 在线设备数量 (假设status为"1"表示在线)
        // 过滤出在线设备 list
        List<SysDevice> onlineDevices = list.stream().filter(device -> "1".equals(device.getState())).toList();

        JnSysRole jnSysRole = new JnSysRole();
        jnSysRole.setUserId(Long.valueOf(userId));
        List<JnSysRole> jnSysRoles = sysRoleService.selectSysRoleList(jnSysRole);
        // 获取角色Id 的集合
        List<String> roleIds = jnSysRoles.stream().map(JnSysRole::getRoleId).collect(Collectors.toList());
        long todayMessages = 0L;
        if (!CollectionUtils.isEmpty(roleIds)) {
            QueryWrapper<SysMessage> todayMessageWrapper = new QueryWrapper<>();
            todayMessageWrapper.in("roleId", roleIds);
            todayMessageWrapper.eq("state", "1");
            todayMessageWrapper.apply("DATE(createTime) = CURDATE()");
            // 今日对话数量 (假设通过SysMessage表统计，createTime为今天的消息)
            todayMessages = sysMessageService.count(todayMessageWrapper);
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("totalDevices", list.size());
        resultMap.put("onlineDevices", onlineDevices.size());
        resultMap.put("todayMessages", todayMessages);

        return AjaxResult.success(resultMap);
    }


    /**
     * 饼图展示 - 来源分布
     */
    @GetMapping("/nologin/getPieChartData")
    public AjaxResult getPieChartData(FxDTO fxDTO) {
        // 构建饼图数据结构
        List<Map<String, Object>> pieData = new ArrayList<>();
        Map<String, Object> deviceData = new HashMap<>();
        // 获取设备来源统计数据
        String userId = fxDTO.getUserId();
        if (StringUtils.isNotEmpty(userId)) {
            //yyyy-MM-dd格式
            String startTime = fxDTO.getStartTime();
            String endTime = fxDTO.getEndTime();
            SysDevice sysDevice = new SysDevice();
            if (StringUtils.isNotEmpty(userId)) {
                sysDevice.setUserId(Long.valueOf(userId));
            }
            List<SysDevice> list = sysDeviceService.selectSysDeviceList(sysDevice);
            long sbNum = 0L;
            if (!CollectionUtils.isEmpty(list)) {
                List<String> deviceIds = list.stream().map(SysDevice::getDeviceId).toList();
                QueryWrapper<SysMessage> todayMessageWrapper = new QueryWrapper<>();
                if (!CollectionUtils.isEmpty(deviceIds)) {
                    todayMessageWrapper.in("deviceId", deviceIds);
                }
                todayMessageWrapper.ne("deviceId", "SYSTEM_H5_DEVICE");
                // 追加开始和结束时间，如果开始时间和结束时间都为空，默认7天
                if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
                    todayMessageWrapper.apply("DATE(createTime) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)");
                } else {
                    // 开始和结束时间 是这种格式yyyy-MM-dd
                    todayMessageWrapper.apply("DATE(createTime) >= '" + startTime + "' AND DATE(createTime) <= '" + endTime + "'");
                }
                // 设备的对话数量
                sbNum = sysMessageService.count(todayMessageWrapper);
            }
            long h5Num = 0L;
            QueryWrapper<SysMessage> todayMessageWrapper = new QueryWrapper<>();
            // 在线渠道
            JnSysRole jnSysRole = new JnSysRole();
            if (StringUtils.isNotEmpty(userId)) {
                jnSysRole.setUserId(Long.valueOf(userId));
            }
            jnSysRole.setType("2");
            List<JnSysRole> listZxqd = sysRoleService.selectSysRoleList(jnSysRole);
            if (!CollectionUtils.isEmpty(listZxqd)) {
                // 获取listZxqd 中的roleId
                List<String> roleIds = listZxqd.stream().map(JnSysRole::getRoleId).toList();
                QueryWrapper<SysMessage> todayMessageWrapperH5 = new QueryWrapper<>();
                todayMessageWrapperH5.in("roleId", roleIds);
                todayMessageWrapperH5.eq("deviceId", "SYSTEM_H5_DEVICE");
                // 追加开始和结束时间，如果开始时间和结束时间都为空，默认7天
                if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
                    todayMessageWrapperH5.apply("DATE(createTime) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)");
                } else {
                    // 开始和结束时间 是这种格式yyyy-MM-dd
                    todayMessageWrapperH5.apply("DATE(createTime) >= '" + startTime + "' AND DATE(createTime) <= '" + endTime + "'");
                }
                h5Num = sysMessageService.count(todayMessageWrapperH5);
            }

            Long total = sbNum + h5Num;
            if (total == 0) {
                deviceData.put("name", "设备");
                deviceData.put("value", 0);
                deviceData.put("percent", 0);
                pieData.add(deviceData);

                // H5页面来源数据
                Map<String, Object> h5Data = new HashMap<>();
                h5Data.put("name", "H5页面");
                h5Data.put("value", 0);
                h5Data.put("percent", 0);
                pieData.add(h5Data);
                return AjaxResult.success(pieData);

            }
            // 计算 设备占比，保留两位小数
            BigDecimal bigDecimal = NumberUtil.div(new BigDecimal(sbNum), new BigDecimal(total), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            // 设备来源数据

            deviceData.put("name", "设备");
            deviceData.put("value", sbNum);
            deviceData.put("percent", bigDecimal);
            pieData.add(deviceData);

            // H5页面来源数据
            Map<String, Object> h5Data = new HashMap<>();
            h5Data.put("name", "H5页面");
            h5Data.put("value", h5Num);
            h5Data.put("percent", new BigDecimal(100).subtract(bigDecimal));
            pieData.add(h5Data);
            return AjaxResult.success(pieData);
        } else {
            deviceData.put("name", "设备");
            deviceData.put("value", 0);
            deviceData.put("percent", 0);
            pieData.add(deviceData);

            // H5页面来源数据
            Map<String, Object> h5Data = new HashMap<>();
            h5Data.put("name", "H5页面");
            h5Data.put("value", 0);
            h5Data.put("percent", 0);
            pieData.add(h5Data);
            return AjaxResult.success(pieData);
        }

    }

    public void setFxtj(FxDTO dto) {
        String roleId = dto.getRoleId();
        String userId = dto.getUserId();
        String startTime = dto.getStartTime();
        String endTime = dto.getEndTime();
        String dzStatus = dto.getDzStatus();
        Integer days = dto.getDays();
        if (StringUtils.isEmpty(startTime) && StringUtils.isEmpty(endTime)) {
            if (days == null) {
                dto.setDays(7);
                days = 7;
            }
        }
        if (StringUtils.isNotEmpty(userId)) {
            // 查询角色
            JnSysRole jnSysRole = new JnSysRole();
            jnSysRole.setUserId(Long.valueOf(userId));
            List<JnSysRole> jnSysRoles = sysRoleService.selectSysRoleList(jnSysRole);
            // 获取角色Id 的集合
            List<String> roleIds = jnSysRoles.stream().map(JnSysRole::getRoleId).collect(Collectors.toList());
            dto.setRoleList(roleIds);
        }

    }

    public void setFxtjH5(FxDTO dto) {
        String roleId = dto.getRoleId();
        String userId = dto.getUserId();
        String startTime = dto.getStartTime();
        String endTime = dto.getEndTime();
        Integer days = dto.getDays();
        if (StringUtils.isEmpty(startTime) && StringUtils.isEmpty(endTime)) {
            if (days == null) {
                dto.setDays(7);
                days = 7;
            }
        }
        List<String> documentTypeList = new ArrayList<>();
        if (StringUtils.isNotEmpty(roleId)) {
            JnSysRole role = sysRoleService.selectSysRoleByRoleId(roleId);
            if (role == null) {
                throw new RuntimeException("配置不存在");
            }
            String documentType = role.getDocumentType();
            if (StringUtils.isNotEmpty(documentType)) {
                documentTypeList = Arrays.asList(documentType.split(","));
            }
        }
        dto.setTypeList(documentTypeList);
        if (StringUtils.isNotEmpty(userId)) {
            // 查询角色
            JnSysRole jnSysRole = new JnSysRole();
            jnSysRole.setUserId(Long.valueOf(userId));
            List<JnSysRole> jnSysRoles = sysRoleService.selectSysRoleList(jnSysRole);
            // 获取角色Id 的集合
            List<String> roleIds = jnSysRoles.stream().map(JnSysRole::getRoleId).collect(Collectors.toList());
            dto.setRoleList(roleIds);
        }

    }


    @Autowired
    private ITPushSubService tPushSubService;


    /**
     * 新增推送主题
     */
    @PostMapping("/addPushSub")
    public AjaxResult addPushSub(@RequestBody TPushSub tPushSub) {
        tPushSub.setUserId(SecurityUtils.getUserIdStr());
        tPushSubService.insertTPushSub(tPushSub);
        return AjaxResult.success();
    }

    /**
     * 修改推送主题
     */
    @PostMapping("/editPushSub")
    public AjaxResult editPushSub(@RequestBody TPushSub tPushSub) {
        tPushSubService.updateTPushSub(tPushSub);
        return AjaxResult.success();
    }

    /**
     * 推送主题列表(分页)
     */
    @GetMapping("/getPushlist")
    public TableDataInfo getPushlist(TPushSub tPushSub) {
        startPage();
        tPushSub.setUserId(SecurityUtils.getUserIdStr());
        List<TPushSub> list = tPushSubService.selectTPushSubList(tPushSub);
        return getDataTable(list);
    }


    /**
     * 推送主题详情
     */
    @GetMapping(value = "/getPushDetail/{id}")
    public AjaxResult getPushDetail(@PathVariable("id") String id) {
        TPushSub sub = tPushSubService.selectTPushSubById(id);
        return AjaxResult.success(sub);
    }


    /**
     * 修改推送主题 开关（1 推送  0 不推送）
     */
    @PostMapping("/uppdatePushSubIsPush")
    public AjaxResult uppdatePushSubIsPush(@RequestBody TPushSub tPushSub) {
        tPushSubService.updateById(tPushSub);
        return AjaxResult.success();
    }


    /**
     * 删除主题推送
     */
    @DeleteMapping("/deletePush/{ids}")
    public AjaxResult deletePush(@PathVariable String[] ids) {
        tPushSubService.deleteTPushSubByIds(ids);
        return AjaxResult.success();
    }


}
